This notebook will contain the code needed to execute our data analysis project and answer the questions we would like to ask of the Spotify and YouTube data from Kaggle.

Load the libraries

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ──────────────────────────────────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.4.0     ✔ purrr   1.0.1
✔ tibble  3.1.8     ✔ dplyr   1.1.0
✔ tidyr   1.3.0     ✔ stringr 1.5.0
✔ readr   2.1.3     ✔ forcats 1.0.0── Conflicts ─────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library(janitor)

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test

Load and clean data

spotify_youtube <- read_csv("data/Spotify_Youtube.csv") %>%
clean_names() %>%
rename(number = x1) %>%
  select(-c(number)) %>%
mutate(duration_secs = duration_ms/1000, duration_mins = duration_ms/60000)
New names:Rows: 20718 Columns: 28── Column specification ─────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (10): Artist, Url_spotify, Track, Album, Album_type, Uri, Url_youtube, Title, Channel, De...
dbl (16): ...1, Danceability, Energy, Key, Loudness, Speechiness, Acousticness, Instrumentaln...
lgl  (2): Licensed, official_video
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
glimpse(spotify_youtube)
Rows: 20,718
Columns: 29
$ artist           <chr> "Gorillaz", "Gorillaz", "Gorillaz", "Gorillaz", "Gorillaz", "Gorillaz"…
$ url_spotify      <chr> "https://open.spotify.com/artist/3AA28KZvwAUcZuOKwyblJQ", "https://ope…
$ track            <chr> "Feel Good Inc.", "Rhinestone Eyes", "New Gold (feat. Tame Impala and …
$ album            <chr> "Demon Days", "Plastic Beach", "New Gold (feat. Tame Impala and Bootie…
$ album_type       <chr> "album", "album", "single", "album", "album", "album", "single", "albu…
$ uri              <chr> "spotify:track:0d28khcov6AiegSCpG5TuT", "spotify:track:1foMv2HQwfQ2vnt…
$ danceability     <dbl> 0.818, 0.676, 0.695, 0.689, 0.663, 0.760, 0.716, 0.726, 0.741, 0.625, …
$ energy           <dbl> 0.705, 0.703, 0.923, 0.739, 0.694, 0.891, 0.897, 0.815, 0.913, 0.877, …
$ key              <dbl> 6, 8, 1, 2, 10, 11, 4, 11, 2, 10, 9, 4, 9, 0, 0, 11, 0, 0, 7, 5, 6, 11…
$ loudness         <dbl> -6.679, -5.815, -3.930, -5.810, -8.627, -5.852, -7.185, -5.886, -3.340…
$ speechiness      <dbl> 0.1770, 0.0302, 0.0522, 0.0260, 0.1710, 0.0372, 0.0629, 0.0313, 0.0465…
$ acousticness     <dbl> 8.36e-03, 8.69e-02, 4.25e-02, 1.51e-05, 2.53e-02, 2.29e-02, 1.20e-02, …
$ instrumentalness <dbl> 2.33e-03, 6.87e-04, 4.69e-02, 5.09e-01, 0.00e+00, 8.69e-02, 2.62e-01, …
$ liveness         <dbl> 0.6130, 0.0463, 0.1160, 0.0640, 0.0698, 0.2980, 0.3250, 0.1120, 0.3250…
$ valence          <dbl> 0.772, 0.852, 0.551, 0.578, 0.525, 0.966, 0.358, 0.462, 0.643, 0.865, …
$ tempo            <dbl> 138.559, 92.761, 108.014, 120.423, 167.953, 120.264, 127.030, 140.158,…
$ duration_ms      <dbl> 222640, 200173, 215150, 233867, 340920, 245000, 274142, 209560, 213750…
$ url_youtube      <chr> "https://www.youtube.com/watch?v=HyHNuVaZJ-k", "https://www.youtube.co…
$ title            <chr> "Gorillaz - Feel Good Inc. (Official Video)", "Gorillaz - Rhinestone E…
$ channel          <chr> "Gorillaz", "Gorillaz", "Gorillaz", "Gorillaz", "Gorillaz", "Gorillaz"…
$ views            <dbl> 693555221, 72011645, 8435055, 211754952, 618480958, 259021161, 451996,…
$ likes            <dbl> 6220896, 1079128, 282142, 1788577, 6197318, 1844658, 11686, 17675, 739…
$ comments         <dbl> 169907, 31003, 7399, 55229, 155930, 72008, 241, 260, 20296, 39240, 121…
$ description      <chr> "Official HD Video for Gorillaz' fantastic track Feel Good Inc.\n\nFol…
$ licensed         <lgl> TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TR…
$ official_video   <lgl> TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRU…
$ stream           <dbl> 1040234854, 310083733, 63063467, 434663559, 617259738, 323850327, 1066…
$ duration_secs    <dbl> 222.640, 200.173, 215.150, 233.867, 340.920, 245.000, 274.142, 209.560…
$ duration_mins    <dbl> 3.710667, 3.336217, 3.585833, 3.897783, 5.682000, 4.083333, 4.569033, …

Basic exploratory analysis

** The dataset has 20,718 rows and 28 columns. There are some NA values within the YouTube data which could serve as a limitation. Similarly, within the YouTube description values, some of the descriptions have emojis or other characters and symbols that could be difficult to work with. Another limitation could arise with the values in the instrumentalness column since they include negative exponents which could also be difficult to work with for different analysis calculations. The original source of the data defines the columns well, otherwise we may make them more complicated. Since the data includes artists whose music is on Spotify but probably not every artist in the world, we would not be able to make assumptions about the music industry as a whole. Another limitation we can notice is that some of the songs that fall under an artist’s most popular songs are feautres of said artist on another song. This can be kind of confusing, but we might be able to work around it using filters once we start more analysis. However, this data is also helpful for answering our question about how collaborations affect an artist’s popularity. One code we would need to make note of is ‘key,’ which denotes pitch notation but we need to find a way to make it easily apparent what the pitch is rather than just seeing a number. There could also be issues with repeat songs when songs are on more than one album, although sometimes it will be the same song but a slightly different rendition.

##Questions Question 1: Which attributes, such as danceability, energy, loudness, etc., tend to have a correlation with the most streamed songs?

Analysis: After using code to select the variables we wanted to work with, we found the correlation coefficient for each song attribute in relation to the number of streams for each song. After finding the correlation coefficients, we calculated the mean among the coefficients for each attribute to average it out. After that, we looked for the maximum value among all the means, and found that danceability and streams had the highest positive correlation coefficient of about 0.073. There were some previous errors due to some values being NA, but using the filter for complete cases got rid of them, and the data we did use was so large that it provided a general idea of which attribute had the greatest correlation to number of streams.

attribute_correlate_stream <- spotify_youtube %>% 
  select(danceability, energy, key, loudness, speechiness, acousticness, instrumentalness, liveness, valence, tempo, stream) %>% 
  filter(complete.cases(.)) %>%
## find the correlation coefficient between each attribute and number of spotify streams 
   mutate(
    dance_cor = cor(danceability, stream),
    energy_cor = cor(energy, stream),
    key_cor = cor(key, stream),
    speech_cor = cor(speechiness, stream),
    acoustic_cor = cor(acousticness, stream),
    instrumental_cor = cor(instrumentalness, stream),
    live_cor = cor(liveness, stream),
    valence_cor = cor(valence, stream),
    tempo_cor = cor(tempo, stream)
  ) %>% 
## find the mean correlation coefficient for each attribute
  summarise(
    mean_dance_cor = mean(dance_cor),
    mean_energy_cor = mean(energy_cor),
    mean_key_cor = mean(key_cor),
    mean_speech_cor = mean(speech_cor),
    mean_acoustic_cor = mean(acoustic_cor),
    mean_instrumental_cor = mean(instrumental_cor),
    mean_live_cor = mean(live_cor),
    mean_valence_cor = mean(valence_cor),
    mean_tempo_cor = mean(tempo_cor)
  )
##output the highest value among the mean coefficients
max_value <- apply(attribute_correlate_stream, 1, max)
  

Question 2: Does higher engagement on YouTube videos lead to more streams of the song from the video on Spotify? Is there a relationship that exists between social engagement and streams?

Analysis: In order to find and map out the correlation between Youtube video views and Spotify streams, we first grouped the data by artist and then summarised the data by the sum of views and sum of streams for each artist. After that, we plotted the data into a scatter plot with a line of best fit, which shows that there is a slight positive correlation between number of views on Youtube and number of streams on Spotify. This means that it can be generally true that as one value increases, so does the other. While doing this, we divided the totals by 1,000,000 because the numbers would have been to large to easily grasp.

##code to find the total number of views and streams (divided by 1,000,000 because numbers were too large to work with)
streams_views <- spotify_youtube %>% 
  select(artist, track, stream, views) %>% 
  mutate(difference = abs(stream-views)) %>% 
  group_by(artist) %>% 
  summarise(
    total_views = sum(views)/1000000,
    total_streams = sum(stream)/1000000,
  )
##create a scatterplot with line of best fit
streams_views %>% 
  ggplot(aes(x=total_streams, y=total_views))+
  geom_point(size=2)+
  theme_minimal()+
  geom_smooth(method = "lm")+
  labs(
    title = "Correlation between an artist's Spotify Streams and Youtube Views",
    x = "Number of Streams on Spotify",
    y = "Number of Views on Youtube"
  )

Question 3: How many videos with a high number of streams are coming from licensed content?

Analysis:

Question 4: How do collaborations or features on a song affect its popularity on Spotify and Youtube? What are the most popular collaborations?

Analysis:

LS0tCnRpdGxlOiAiRGF0YSBBbmFseXNpcyBQcm9qZWN0IgpuYW1lczogIktpZXJzdGVuIEhhY2tlciBhbmQgU2hlcndpbi1OZXN0b3IgRXNndWVycmEiCmRhdGU6ICI0LTExLTIwMjMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgbm90ZWJvb2sgd2lsbCBjb250YWluIHRoZSBjb2RlIG5lZWRlZCB0byBleGVjdXRlIG91ciBkYXRhIGFuYWx5c2lzIHByb2plY3QgYW5kIGFuc3dlciB0aGUgcXVlc3Rpb25zIHdlIHdvdWxkIGxpa2UgdG8gYXNrIG9mIHRoZSBTcG90aWZ5IGFuZCBZb3VUdWJlIGRhdGEgZnJvbSBLYWdnbGUuCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMjIyBMb2FkIHRoZSBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShqYW5pdG9yKQpgYGAKCiMjIyBMb2FkIGFuZCBjbGVhbiBkYXRhCmBgYHtyfQpzcG90aWZ5X3lvdXR1YmUgPC0gcmVhZF9jc3YoImRhdGEvU3BvdGlmeV9Zb3V0dWJlLmNzdiIpICU+JQpjbGVhbl9uYW1lcygpICU+JQpyZW5hbWUobnVtYmVyID0geDEpICU+JQogIHNlbGVjdCgtYyhudW1iZXIpKSAlPiUKbXV0YXRlKGR1cmF0aW9uX3NlY3MgPSBkdXJhdGlvbl9tcy8xMDAwLCBkdXJhdGlvbl9taW5zID0gZHVyYXRpb25fbXMvNjAwMDApCgpnbGltcHNlKHNwb3RpZnlfeW91dHViZSkKCgpgYGAKCiMjIyBCYXNpYyBleHBsb3JhdG9yeSBhbmFseXNpcwoqKiBUaGUgZGF0YXNldCBoYXMgMjAsNzE4IHJvd3MgYW5kIDI4IGNvbHVtbnMuIFRoZXJlIGFyZSBzb21lIE5BIHZhbHVlcyB3aXRoaW4gdGhlIFlvdVR1YmUgZGF0YSB3aGljaCBjb3VsZCBzZXJ2ZSBhcyBhIGxpbWl0YXRpb24uIFNpbWlsYXJseSwgd2l0aGluIHRoZSBZb3VUdWJlIGRlc2NyaXB0aW9uIHZhbHVlcywgc29tZSBvZiB0aGUgZGVzY3JpcHRpb25zIGhhdmUgZW1vamlzIG9yIG90aGVyIGNoYXJhY3RlcnMgYW5kIHN5bWJvbHMgdGhhdCBjb3VsZCBiZSBkaWZmaWN1bHQgdG8gd29yayB3aXRoLiBBbm90aGVyIGxpbWl0YXRpb24gY291bGQgYXJpc2Ugd2l0aCB0aGUgdmFsdWVzIGluIHRoZSBpbnN0cnVtZW50YWxuZXNzIGNvbHVtbiBzaW5jZSB0aGV5IGluY2x1ZGUgbmVnYXRpdmUgZXhwb25lbnRzIHdoaWNoIGNvdWxkIGFsc28gYmUgZGlmZmljdWx0IHRvIHdvcmsgd2l0aCBmb3IgZGlmZmVyZW50IGFuYWx5c2lzIGNhbGN1bGF0aW9ucy4gVGhlIG9yaWdpbmFsIHNvdXJjZSBvZiB0aGUgZGF0YSBkZWZpbmVzIHRoZSBjb2x1bW5zIHdlbGwsIG90aGVyd2lzZSB3ZSBtYXkgbWFrZSB0aGVtIG1vcmUgY29tcGxpY2F0ZWQuIFNpbmNlIHRoZSBkYXRhIGluY2x1ZGVzIGFydGlzdHMgd2hvc2UgbXVzaWMgaXMgb24gU3BvdGlmeSBidXQgcHJvYmFibHkgbm90IGV2ZXJ5IGFydGlzdCBpbiB0aGUgd29ybGQsIHdlIHdvdWxkIG5vdCBiZSBhYmxlIHRvIG1ha2UgYXNzdW1wdGlvbnMgYWJvdXQgdGhlIG11c2ljIGluZHVzdHJ5IGFzIGEgd2hvbGUuIEFub3RoZXIgbGltaXRhdGlvbiB3ZSBjYW4gbm90aWNlIGlzIHRoYXQgc29tZSBvZiB0aGUgc29uZ3MgdGhhdCBmYWxsIHVuZGVyIGFuIGFydGlzdCdzIG1vc3QgcG9wdWxhciBzb25ncyBhcmUgZmVhdXRyZXMgb2Ygc2FpZCBhcnRpc3Qgb24gYW5vdGhlciBzb25nLiBUaGlzIGNhbiBiZSBraW5kIG9mIGNvbmZ1c2luZywgYnV0IHdlIG1pZ2h0IGJlIGFibGUgdG8gd29yayBhcm91bmQgaXQgdXNpbmcgZmlsdGVycyBvbmNlIHdlIHN0YXJ0IG1vcmUgYW5hbHlzaXMuIEhvd2V2ZXIsIHRoaXMgZGF0YSBpcyBhbHNvIGhlbHBmdWwgZm9yIGFuc3dlcmluZyBvdXIgcXVlc3Rpb24gYWJvdXQgaG93IGNvbGxhYm9yYXRpb25zIGFmZmVjdCBhbiBhcnRpc3QncyBwb3B1bGFyaXR5LiBPbmUgY29kZSB3ZSB3b3VsZCBuZWVkIHRvIG1ha2Ugbm90ZSBvZiBpcyAna2V5LCcgd2hpY2ggZGVub3RlcyBwaXRjaCBub3RhdGlvbiBidXQgd2UgbmVlZCB0byBmaW5kIGEgd2F5IHRvIG1ha2UgaXQgZWFzaWx5IGFwcGFyZW50IHdoYXQgdGhlIHBpdGNoIGlzIHJhdGhlciB0aGFuIGp1c3Qgc2VlaW5nIGEgbnVtYmVyLiBUaGVyZSBjb3VsZCBhbHNvIGJlIGlzc3VlcyB3aXRoIHJlcGVhdCBzb25ncyB3aGVuIHNvbmdzIGFyZSBvbiBtb3JlIHRoYW4gb25lIGFsYnVtLCBhbHRob3VnaCBzb21ldGltZXMgaXQgd2lsbCBiZSB0aGUgc2FtZSBzb25nIGJ1dCBhIHNsaWdodGx5IGRpZmZlcmVudCByZW5kaXRpb24uCgojI1F1ZXN0aW9ucwpRdWVzdGlvbiAxOiBXaGljaCBhdHRyaWJ1dGVzLCBzdWNoIGFzIGRhbmNlYWJpbGl0eSwgZW5lcmd5LCBsb3VkbmVzcywgZXRjLiwgdGVuZCB0byBoYXZlIGEgY29ycmVsYXRpb24gd2l0aCB0aGUgbW9zdCBzdHJlYW1lZCBzb25ncz8KCkFuYWx5c2lzOiBBZnRlciB1c2luZyBjb2RlIHRvIHNlbGVjdCB0aGUgdmFyaWFibGVzIHdlIHdhbnRlZCB0byB3b3JrIHdpdGgsIHdlIGZvdW5kIHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBmb3IgZWFjaCBzb25nIGF0dHJpYnV0ZSBpbiByZWxhdGlvbiB0byB0aGUgbnVtYmVyIG9mIHN0cmVhbXMgZm9yIGVhY2ggc29uZy4gQWZ0ZXIgZmluZGluZyB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnRzLCB3ZSBjYWxjdWxhdGVkIHRoZSBtZWFuIGFtb25nIHRoZSBjb2VmZmljaWVudHMgZm9yIGVhY2ggYXR0cmlidXRlIHRvIGF2ZXJhZ2UgaXQgb3V0LiBBZnRlciB0aGF0LCB3ZSBsb29rZWQgZm9yIHRoZSBtYXhpbXVtIHZhbHVlIGFtb25nIGFsbCB0aGUgbWVhbnMsIGFuZCBmb3VuZCB0aGF0IGRhbmNlYWJpbGl0eSBhbmQgc3RyZWFtcyBoYWQgdGhlIGhpZ2hlc3QgcG9zaXRpdmUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgYWJvdXQgMC4wNzMuIFRoZXJlIHdlcmUgc29tZSBwcmV2aW91cyBlcnJvcnMgZHVlIHRvIHNvbWUgdmFsdWVzIGJlaW5nIE5BLCBidXQgdXNpbmcgdGhlIGZpbHRlciBmb3IgY29tcGxldGUgY2FzZXMgZ290IHJpZCBvZiB0aGVtLCBhbmQgdGhlIGRhdGEgd2UgZGlkIHVzZSB3YXMgc28gbGFyZ2UgdGhhdCBpdCBwcm92aWRlZCBhIGdlbmVyYWwgaWRlYSBvZiB3aGljaCBhdHRyaWJ1dGUgaGFkIHRoZSBncmVhdGVzdCBjb3JyZWxhdGlvbiB0byBudW1iZXIgb2Ygc3RyZWFtcy4KCmBgYHtyfQphdHRyaWJ1dGVfY29ycmVsYXRlX3N0cmVhbSA8LSBzcG90aWZ5X3lvdXR1YmUgJT4lIAogIHNlbGVjdChkYW5jZWFiaWxpdHksIGVuZXJneSwga2V5LCBsb3VkbmVzcywgc3BlZWNoaW5lc3MsIGFjb3VzdGljbmVzcywgaW5zdHJ1bWVudGFsbmVzcywgbGl2ZW5lc3MsIHZhbGVuY2UsIHRlbXBvLCBzdHJlYW0pICU+JSAKICBmaWx0ZXIoY29tcGxldGUuY2FzZXMoLikpICU+JQojIyBmaW5kIHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBiZXR3ZWVuIGVhY2ggYXR0cmlidXRlIGFuZCBudW1iZXIgb2Ygc3BvdGlmeSBzdHJlYW1zIAogICBtdXRhdGUoCiAgICBkYW5jZV9jb3IgPSBjb3IoZGFuY2VhYmlsaXR5LCBzdHJlYW0pLAogICAgZW5lcmd5X2NvciA9IGNvcihlbmVyZ3ksIHN0cmVhbSksCiAgICBrZXlfY29yID0gY29yKGtleSwgc3RyZWFtKSwKICAgIHNwZWVjaF9jb3IgPSBjb3Ioc3BlZWNoaW5lc3MsIHN0cmVhbSksCiAgICBhY291c3RpY19jb3IgPSBjb3IoYWNvdXN0aWNuZXNzLCBzdHJlYW0pLAogICAgaW5zdHJ1bWVudGFsX2NvciA9IGNvcihpbnN0cnVtZW50YWxuZXNzLCBzdHJlYW0pLAogICAgbGl2ZV9jb3IgPSBjb3IobGl2ZW5lc3MsIHN0cmVhbSksCiAgICB2YWxlbmNlX2NvciA9IGNvcih2YWxlbmNlLCBzdHJlYW0pLAogICAgdGVtcG9fY29yID0gY29yKHRlbXBvLCBzdHJlYW0pCiAgKSAlPiUgCiMjIGZpbmQgdGhlIG1lYW4gY29ycmVsYXRpb24gY29lZmZpY2llbnQgZm9yIGVhY2ggYXR0cmlidXRlCiAgc3VtbWFyaXNlKAogICAgbWVhbl9kYW5jZV9jb3IgPSBtZWFuKGRhbmNlX2NvciksCiAgICBtZWFuX2VuZXJneV9jb3IgPSBtZWFuKGVuZXJneV9jb3IpLAogICAgbWVhbl9rZXlfY29yID0gbWVhbihrZXlfY29yKSwKICAgIG1lYW5fc3BlZWNoX2NvciA9IG1lYW4oc3BlZWNoX2NvciksCiAgICBtZWFuX2Fjb3VzdGljX2NvciA9IG1lYW4oYWNvdXN0aWNfY29yKSwKICAgIG1lYW5faW5zdHJ1bWVudGFsX2NvciA9IG1lYW4oaW5zdHJ1bWVudGFsX2NvciksCiAgICBtZWFuX2xpdmVfY29yID0gbWVhbihsaXZlX2NvciksCiAgICBtZWFuX3ZhbGVuY2VfY29yID0gbWVhbih2YWxlbmNlX2NvciksCiAgICBtZWFuX3RlbXBvX2NvciA9IG1lYW4odGVtcG9fY29yKQogICkKIyNvdXRwdXQgdGhlIGhpZ2hlc3QgdmFsdWUgYW1vbmcgdGhlIG1lYW4gY29lZmZpY2llbnRzCm1heF92YWx1ZSA8LSBhcHBseShhdHRyaWJ1dGVfY29ycmVsYXRlX3N0cmVhbSwgMSwgbWF4KQogIApgYGAKClF1ZXN0aW9uIDI6IERvZXMgaGlnaGVyIGVuZ2FnZW1lbnQgb24gWW91VHViZSB2aWRlb3MgbGVhZCB0byBtb3JlIHN0cmVhbXMgb2YgdGhlIHNvbmcgZnJvbSB0aGUgdmlkZW8gb24gU3BvdGlmeT8gSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgdGhhdCBleGlzdHMgYmV0d2VlbiBzb2NpYWwgZW5nYWdlbWVudCBhbmQgc3RyZWFtcz8KCkFuYWx5c2lzOiBJbiBvcmRlciB0byBmaW5kIGFuZCBtYXAgb3V0IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIFlvdXR1YmUgdmlkZW8gdmlld3MgYW5kIFNwb3RpZnkgc3RyZWFtcywgd2UgZmlyc3QgZ3JvdXBlZCB0aGUgZGF0YSBieSBhcnRpc3QgYW5kIHRoZW4gc3VtbWFyaXNlZCB0aGUgZGF0YSBieSB0aGUgc3VtIG9mIHZpZXdzIGFuZCBzdW0gb2Ygc3RyZWFtcyBmb3IgZWFjaCBhcnRpc3QuIEFmdGVyIHRoYXQsIHdlIHBsb3R0ZWQgdGhlIGRhdGEgaW50byBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgbGluZSBvZiBiZXN0IGZpdCwgd2hpY2ggc2hvd3MgdGhhdCB0aGVyZSBpcyBhIHNsaWdodCBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG51bWJlciBvZiB2aWV3cyBvbiBZb3V0dWJlIGFuZCBudW1iZXIgb2Ygc3RyZWFtcyBvbiBTcG90aWZ5LiBUaGlzIG1lYW5zIHRoYXQgaXQgY2FuIGJlIGdlbmVyYWxseSB0cnVlIHRoYXQgYXMgb25lIHZhbHVlIGluY3JlYXNlcywgc28gZG9lcyB0aGUgb3RoZXIuIFdoaWxlIGRvaW5nIHRoaXMsIHdlIGRpdmlkZWQgdGhlIHRvdGFscyBieSAxLDAwMCwwMDAgYmVjYXVzZSB0aGUgbnVtYmVycyB3b3VsZCBoYXZlIGJlZW4gdG8gbGFyZ2UgdG8gZWFzaWx5IGdyYXNwLiAKCmBgYHtyfQojI2NvZGUgdG8gZmluZCB0aGUgdG90YWwgbnVtYmVyIG9mIHZpZXdzIGFuZCBzdHJlYW1zIChkaXZpZGVkIGJ5IDEsMDAwLDAwMCBiZWNhdXNlIG51bWJlcnMgd2VyZSB0b28gbGFyZ2UgdG8gd29yayB3aXRoKQpzdHJlYW1zX3ZpZXdzIDwtIHNwb3RpZnlfeW91dHViZSAlPiUgCiAgc2VsZWN0KGFydGlzdCwgdHJhY2ssIHN0cmVhbSwgdmlld3MpICU+JSAKICBtdXRhdGUoZGlmZmVyZW5jZSA9IGFicyhzdHJlYW0tdmlld3MpKSAlPiUgCiAgZ3JvdXBfYnkoYXJ0aXN0KSAlPiUgCiAgc3VtbWFyaXNlKAogICAgdG90YWxfdmlld3MgPSBzdW0odmlld3MpLzEwMDAwMDAsCiAgICB0b3RhbF9zdHJlYW1zID0gc3VtKHN0cmVhbSkvMTAwMDAwMCwKICApCiMjY3JlYXRlIGEgc2NhdHRlcnBsb3Qgd2l0aCBsaW5lIG9mIGJlc3QgZml0CnN0cmVhbXNfdmlld3MgJT4lIAogIGdncGxvdChhZXMoeD10b3RhbF9zdHJlYW1zLCB5PXRvdGFsX3ZpZXdzKSkrCiAgZ2VvbV9wb2ludChzaXplPTIpKwogIHRoZW1lX21pbmltYWwoKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSsKICBsYWJzKAogICAgdGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBhbiBhcnRpc3QncyBTcG90aWZ5IFN0cmVhbXMgYW5kIFlvdXR1YmUgVmlld3MiLAogICAgeCA9ICJOdW1iZXIgb2YgU3RyZWFtcyBvbiBTcG90aWZ5IiwKICAgIHkgPSAiTnVtYmVyIG9mIFZpZXdzIG9uIFlvdXR1YmUiCiAgKQpgYGAKClF1ZXN0aW9uIDM6IEhvdyBtYW55IHZpZGVvcyB3aXRoIGEgaGlnaCBudW1iZXIgb2Ygc3RyZWFtcyBhcmUgY29taW5nIGZyb20gbGljZW5zZWQgY29udGVudD8KCkFuYWx5c2lzOiAKCmBgYHtyfQp5b3V0dWJlX2hpZ2hfdmlld3MgPC0gc3BvdGlmeV95b3V0dWJlICU+JQogIGZpbHRlcih2aWV3cyA+IDUwMDAwMDAwMCkKCnlvdXR1YmVfaGlnaF92aWV3cyAlPiUKICBncm91cF9ieShhcnRpc3QpICU+JQogIHN1bW1hcmlzZSAoCiAgICBjb3VudF9saWNlbnNlZCA9IG4oKQogICkgJT4lCiAgYXJyYW5nZShkZXNjKGNvdW50X2xpY2Vuc2VkKSkKCnlvdXR1YmVfaGlnaF92aWV3cyAlPiUKICBmaWx0ZXIobGljZW5zZWQgPT0gRkFMU0UpIAoKeW91dHViZV9oaWdoX3ZpZXdzICU+JQogIGdyb3VwX2J5KGNoYW5uZWwpICU+JQogIGZpbHRlcihsaWNlbnNlZCA9PSBGQUxTRSwgb2ZmaWNpYWxfdmlkZW8gPT0gVFJVRSkKCiMjaG93IHRvIGdldCB0b3RhbHMgZm9yIGxpY2Vuc2VkIGFuZCB1bmxpY2Vuc2VkPwpgYGAKClF1ZXN0aW9uIDQ6IEhvdyBkbyBjb2xsYWJvcmF0aW9ucyBvciBmZWF0dXJlcyBvbiBhIHNvbmcgYWZmZWN0IGl0cyBwb3B1bGFyaXR5IG9uIFNwb3RpZnkgYW5kIFlvdXR1YmU/IFdoYXQgYXJlIHRoZSBtb3N0IHBvcHVsYXIgY29sbGFib3JhdGlvbnM/CgpBbmFseXNpczoKCmBgYHtyfQpzb25nX2ZlYXR1cmVzIDwtIHNwb3RpZnlfeW91dHViZSAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdCh0cmFjaywgJ2ZlYXQuJykpCgpzb25nX2ZlYXR1cmVzICU+JQogIGdyb3VwX2J5KGFydGlzdCwgc3RyZWFtKSAlPiUKICBhcnJhbmdlKGRlc2Moc3RyZWFtKSkKCiMjSG93IHRvIGNvdW50IGhvdyBtYW55IGZlYXR1cmVzIGFuIGFydGlzdCBoYXMsIGlzc3VlIG9mIHJlcGVhdHMgd2hlcmUgdGhlIHNhbWUgc29uZyBpcyBsaXN0ZWQgdW5kZXIgbW9yZSB0aGFuIG9uZSBhcnRpc3QgKE1hY2tlbG1vcmUgYW5kIFJ5YW4gTGV3aXMpCgpgYGAKCg==